#pragma once 
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

//环形队列，用数组的高速缓冲存储命中率更高。用信号量实现生产者push，消费者pop，可同时访问环形队列，但是互斥访问自己需要的那块空间（两个mutex）
template <class T,size_t N= 5>
class RingQueue
{
public:
    RingQueue()
        :_bq(N)
        ,_index_c(0)
        ,_index_p(0)
    {
        sem_init(&_roomsem,0,N);//开始5个空间，0个数据
        sem_init(&_datasem,0,0);
        pthread_mutex_init(&_pmutex,nullptr);
        pthread_mutex_init(&_cmutex,nullptr);
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
        sem_destroy(&_roomsem);
        sem_destroy(&_datasem);
    }

    void push(const T& task)
    {
        sem_wait(&_roomsem);               //信号量自己实现了判断为0相等还是满了相等，自行阻塞对应的线程。无需自己条件变量控制
        pthread_mutex_lock(&_pmutex);       //当生产者消费者到达同一个空间时，无需实现互斥访问，因信号量已经阻塞对应的一个了

        //..实现放任务
        _bq[_index_p] = task;
        cout<<"生产者下标:"<<_index_p<<endl;
        _index_p++;
        _index_p%=_bq.size();

        pthread_mutex_unlock(&_pmutex);
        sem_post(&_datasem);

    }

    T pop()
    {
        sem_wait(&_datasem);
        pthread_mutex_lock(&_cmutex);

        //..实现放任务
        T temp = _bq[_index_c];
        cout<<"消费者下标:"<<_index_c<<endl;
        _index_c++;
        _index_c%=_bq.size();

        pthread_mutex_unlock(&_cmutex);
        sem_post(&_roomsem);
        return temp;
    }
private: 
    vector<T> _bq;
    size_t _index_c;        //环形队列用下标访问自己所需元素
    size_t _index_p;
    sem_t _roomsem;          //这个不是ifelse，信号量是资源的计数器实现就是判断资源是否为零
    sem_t _datasem;          //用两个信号量表示生产者消费者的可用资源，底层用汇编代码swap，exchage可以直接原子交换寄存器和内存的值，实现原子性

    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;
};

